package com.zallds.fabric.util;

import org.apache.log4j.Logger;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * FabricUtils,暂时不关注CA方面的东西
 */
public class FabricUtils {
    //日志记录
    private static Logger logger = Logger.getLogger(FabricUtils.class);

    //CA客户端
    public static HFClient client = null;

    public static CryptoSuite cs = null;

    public static HashMap<String, SOrg> orgHashMap = null;

    public static ChaincodeID cid = null;

    public static User peer0org1 = null;



    public static void init() throws Exception {
        cs = CryptoSuite.Factory.getCryptoSuite();
        cid = ChaincodeID.newBuilder().setName("sacc").build();
        client = HFClient.createNewInstance();
        client.setCryptoSuite(cs);
        orgHashMap = OrgConfig.getSOrg();
        peer0org1 = orgHashMap.get("org1").getAdmin();
        client.setUserContext(peer0org1);
    }

    /*
     *   实现插入数据
     * */
    public static void instert(Channel channel, DataRecord data) throws Exception {
        TransactionProposalRequest req = client.newTransactionProposalRequest();
        req.setChaincodeID(cid);
        req.setFcn("set");
        req.setArgs(data.toStringArray());
        Map<String, byte[]> tm2 = new HashMap<>();
        //代码来自End2End
        tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8));
        tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8));
        tm2.put("result", ":)".getBytes(UTF_8));
        req.setTransientMap(tm2);
        Collection<ProposalResponse> resps = channel.sendTransactionProposal(req);
        for (ProposalResponse resp : resps) {
            String payload = new String(resp.getChaincodeActionResponsePayload());
            logger.debug("payload!!!!!!!: " + payload);
        }
        channel.sendTransaction(resps);
    }

    /*
     *   实现给定的Key查询数据
     * */
    public static void query(Channel channel, String key) throws Exception {
        QueryByChaincodeRequest req = client.newQueryProposalRequest();
        ChaincodeID cid = ChaincodeID.newBuilder().setName("sacc").build();
        req.setChaincodeID(cid);
        req.setFcn("query");
        req.setArgs(new String[]{key});
        Collection<ProposalResponse> resps = channel.queryByChaincode(req);
        for (ProposalResponse resp : resps) {
            String payload = new String(resp.getChaincodeActionResponsePayload());
            logger.debug("payload!!!!!!!: " + payload);
        }
    }

    public static void queryMoney(Channel channel,String key) throws ProposalException, InvalidArgumentException {
        QueryByChaincodeRequest req = client.newQueryProposalRequest();
        ChaincodeID cid = ChaincodeID.newBuilder().setName(CommonUtils.chainCodeName).build();
        req.setChaincodeID(cid);
        req.setFcn("query");
        req.setArgs(key);
        System.out.println("Querying for " + key);
        Collection<ProposalResponse> resps = channel.queryByChaincode(req);
        for (ProposalResponse resp : resps) {
            //System.out.println("response: " + resp.getMessage());
            String payload = new String(resp.getChaincodeActionResponsePayload());
            System.out.println("response: " + payload);
        }
    }

    /**
     * 更新账本
     * @throws Exception
     */
    public static void invoke(Channel channel) throws Exception {

        // 构建proposal
        TransactionProposalRequest req = client.newTransactionProposalRequest();
        // 指定要调用的chaincode
        ChaincodeID cid = ChaincodeID.newBuilder().setName(CommonUtils.chainCodeName).build();
        req.setChaincodeID(cid);
        req.setFcn("invoke");
        req.setArgs("a","b","10");
        // 发送proprosal
        Collection<ProposalResponse> resps = channel.sendTransactionProposal(req);
        for (ProposalResponse resp : resps) {
            //System.out.println("response: " + resp.getMessage());
            String payload = new String(resp.getChaincodeActionResponsePayload());
            System.out.println("response: " + payload);
        }

        // 提交给orderer节点
        channel.sendTransaction(resps);
    }


    /**
     * 新增
     * @throws Exception
     */
    public static void add(Channel channel) throws Exception {

        // 构建proposal
        TransactionProposalRequest req = client.newTransactionProposalRequest();
        // 指定要调用的chaincode
        ChaincodeID cid = ChaincodeID.newBuilder().setName(CommonUtils.chainCodeName).build();
        req.setChaincodeID(cid);
        req.setFcn("set");
        req.setArgs("c","300");
        // 发送proprosal
        Collection<ProposalResponse> resps = channel.sendTransactionProposal(req);



        // 提交给orderer节点
        channel.sendTransaction(resps);
    }


    /***
     * 实例化链码
     * @return
     */
    public static Map<String,String> instantiate(Channel channel) throws ProposalException, InvalidArgumentException, IOException, ChaincodeEndorsementPolicyParseException {
        UpgradeProposalRequest upgradeProposalRequest = client.newUpgradeProposalRequest();
        // 指定要调用的chaincode
        ChaincodeID cid = ChaincodeID.newBuilder().setName(CommonUtils.chainCodeName).setVersion("1.0").build();;
        upgradeProposalRequest.setChaincodeID(cid);
        upgradeProposalRequest.setProposalWaitTime(100000);
        upgradeProposalRequest.setFcn("init");
        upgradeProposalRequest.setArgs(new String[]{"c","100","d","200"});

        ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy();
        chaincodeEndorsementPolicy.fromYamlFile(new File("D:\\Des\\fabric-java-sdk-demo\\src\\main\\resource\\chaincodeendorsementpolicy.yaml"));
        upgradeProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);

        Map<String, byte[]> tm2 = new HashMap<>();
        tm2.put("HyperLedgerFabric", "InstantiateProposalRequest:JavaSDK".getBytes(UTF_8));
        tm2.put("method", "InstantiateProposalRequest".getBytes(UTF_8));
        tm2.put("result", ":)".getBytes(UTF_8));
        upgradeProposalRequest.setTransientMap(tm2);

        Collection<ProposalResponse> instantiateProposalResponses = channel.sendUpgradeProposal(upgradeProposalRequest);
        return null;
    }















    /**
     * 获取crypto-config配置路径
     *
     * @return /WEB-INF/classes/fabric/fabric.crypto-config/
     */
    private static String getCryptoConfigPath() {
        String directorys = FabricUtils.class.getClassLoader().getResource("com/zallds/fabric").getFile();
        File directory = new File(directorys);

        return directory.getPath() + "/fabric/crypto-config/";
    }

    public static Properties getOrderProperty(){

        File ordererCert = Paths.get(getCryptoConfigPath(), "/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt").toFile();

        Properties ordererProperties = new Properties();
        ordererProperties.setProperty("pemFile", ordererCert.getAbsolutePath());
        ordererProperties.setProperty("hostnameOverride", "orderer.example.com");
        ordererProperties.setProperty("sslProvider", "openSSL");
        ordererProperties.setProperty("negotiationType", "TLS");
        ordererProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000);
        // 设置keepAlive以避免在不活跃的http2连接上超时的例子。在5分钟内，需要对服务器端进行更改，以接受更快的ping速率。
        ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[]{5L, TimeUnit.MINUTES});
        ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[]{8L, TimeUnit.SECONDS});
        ordererProperties.setProperty("ordererWaitTimeMilliSecs", "300000");
        return ordererProperties;
    }


    public static Properties getPeerProperty(String orgDomainName, String peerName){

        File peerCert = Paths.get(getCryptoConfigPath(), "/peerOrganizations", orgDomainName, "peers", peerName, "tls/server.crt")
                .toFile();
        Properties peerProperties = new Properties();
        peerProperties.setProperty("pemFile", peerCert.getAbsolutePath());
        // ret.setProperty("trustServerCertificate", "true"); //testing
        // environment only NOT FOR PRODUCTION!
        peerProperties.setProperty("hostnameOverride", peerName);
        peerProperties.setProperty("sslProvider", "openSSL");
        peerProperties.setProperty("negotiationType", "TLS");
        // 在grpc的NettyChannelBuilder上设置特定选项
        peerProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000);
        return peerProperties;
    }


}
